// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:front_end/src/base/messages.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/transformations/flags.dart';

import '../base/compiler_context.dart';
import '../base/constant_context.dart' show ConstantContext;
import '../base/identifiers.dart' show Identifier;
import '../base/local_scope.dart';
import '../base/lookup_result.dart';
import '../builder/builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/library_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/type_builder.dart';
import '../dill/dill_class_builder.dart';
import '../source/source_class_builder.dart';
import '../source/source_constructor_builder.dart';
import '../source/source_enum_builder.dart';
import '../source/source_extension_builder.dart';
import '../source/source_extension_type_declaration_builder.dart';
import '../source/source_library_builder.dart';
import '../source/source_member_builder.dart';
import '../source/source_property_builder.dart';
import '../source/source_type_alias_builder.dart';
import '../type_inference/inference_results.dart'
    show InitializerInferenceResult;
import '../type_inference/type_inferrer.dart' show TypeInferrer;
import 'internal_ast.dart';

/// Interface that defines the interface between the [BodyBuilder] and the
/// member/declaration whose AST is being built.
abstract class BodyBuilderContext {
  final BodyBuilderDeclarationContext declarationContext;

  final bool _isDeclarationInstanceMember;

  BodyBuilderContext(
    LibraryBuilder libraryBuilder,
    DeclarationBuilder? declarationBuilder, {
    required bool isDeclarationInstanceMember,
  }) : _isDeclarationInstanceMember = isDeclarationInstanceMember,
       declarationContext = new BodyBuilderDeclarationContext(
         libraryBuilder,
         declarationBuilder,
       );

  /// Returns `true` if the enclosing declaration declares a const constructor.
  bool get declarationDeclaresConstConstructor =>
      declarationContext.declaresConstConstructor;

  /// Returns the file offset of the name of the member whose body is being
  /// built.
  ///
  /// For an unnamed constructor this is offset of the class name.
  ///
  /// This is used for error reporting.
  // TODO(johnniwinther): Replaces this with something better. It is not only
  // used for error reporting.
  int get memberNameOffset {
    throw new UnsupportedError("${runtimeType}.memberNameOffset");
  }

  /// Returns the length of the name of the member whose body is being built.
  ///
  /// For an unnamed constructor this is 0.
  ///
  /// This is used for error reporting.
  // TODO(johnniwinther): Replaces this with something better.
  int get memberNameLength {
    throw new UnsupportedError('${runtimeType}.memberNameLength');
  }

  /// Looks up the member by the given [name] in the superclass of the enclosing
  /// class.
  ///
  /// If [isSetter] is `true`, a setable is returned, otherwise a getable is
  /// returned.
  Member? lookupSuperMember(
    ClassHierarchy hierarchy,
    Name name, {
    bool isSetter = false,
  }) {
    return declarationContext.lookupSuperMember(
      hierarchy,
      name,
      isSetter: isSetter,
    );
  }

  /// Looks up the constructor by the given [name] in the enclosing declaration.
  Builder? lookupConstructor(Name name) {
    return declarationContext.lookupConstructor(name);
  }

  /// Creates an [Initializer] for a redirecting initializer call to
  /// [constructorBuilder] with the given [arguments] from within a constructor
  /// in the same class.
  Initializer buildRedirectingInitializer(
    Builder constructorBuilder,
    ArgumentsImpl arguments, {
    required int fileOffset,
  }) {
    return declarationContext.buildRedirectingInitializer(
      constructorBuilder,
      arguments,
      fileOffset: fileOffset,
    );
  }

  /// Looks up the constructor by the given [name] in the superclass of the
  /// enclosing class.
  MemberLookupResult? lookupSuperConstructor(
    String name,
    LibraryBuilder accessingLibrary,
  ) {
    return declarationContext.lookupSuperConstructor(name, accessingLibrary);
  }

  /// Looks up the member by the given [name] declared in the enclosing
  /// declaration or library.
  LookupResult? lookupLocalMember(String name) {
    return declarationContext.lookupLocalMember(name);
  }

  /// Returns `true` if the enclosing entity is an extension type.
  bool get isExtensionTypeDeclaration =>
      declarationContext.isExtensionTypeDeclaration;

  /// Returns `true` if the enclosing entity is an extension.
  bool get isExtensionDeclaration => declarationContext.isExtensionDeclaration;

  /// Returns the [FormalParameterBuilder] by the given [name] declared in the
  /// member whose body is being built.
  FormalParameterBuilder? getFormalParameterByName(Identifier identifier) {
    if (formals != null) {
      List<FormalParameterBuilder> formals = this.formals!;
      for (int i = 0; i < formals.length; i++) {
        FormalParameterBuilder formal = formals[i];
        if (formal.isWildcard &&
            identifier.name == '_' &&
            formal.fileOffset == identifier.nameOffset) {
          return formal;
        }
        if (formal.name == identifier.name &&
            formal.fileOffset == identifier.nameOffset) {
          return formal;
        }
      }
      // Coverage-ignore(suite): Not run.
      // If we have any formals we should find the one we're looking for.
      assert(false, "$identifier not found in $formals");
    }
    return null;
  }

  /// Returns the [FunctionNode] for the function body currently being built.
  FunctionNode get function {
    throw new UnsupportedError('${runtimeType}.function');
  }

  /// Returns `true` if the member whose body is being built is a non-factory
  /// constructor declaration.
  bool get isConstructor => false;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is a non-factory
  /// constructor declaration marked as `external`.
  bool get isExternalConstructor => false;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is a constructor,
  /// factory, method, getter, or setter marked as `external`.
  bool get isExternalFunction => false;

  /// Returns `true` if the member whose body is being built is a setter
  /// declaration.
  bool get isSetter => false;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is a non-factory
  /// constructor declaration marked as `const`.
  bool get isConstConstructor => false;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is a (redirecting)
  /// factory declaration.
  bool get isFactory => false;

  /// Returns `true` if the member whose body is being built is marked as
  /// native.
  bool get isNativeMethod => false;

  /// Returns `true` if the member whose body is built is an instance member
  /// or a non-factory constructor.
  bool get isDeclarationInstanceContext {
    return _isDeclarationInstanceMember || isConstructor;
  }

  /// Returns `true` if the member whose body is being built is a redirecting
  /// factory declaration.
  bool get isRedirectingFactory => false;

  /// Returns the constructor name, including the class name, of the immediate
  /// target of a redirecting factory constructor.
  ///
  /// This is only supported if [isRedirectingFactory] is `true`.
  ///
  /// This is used for error reporting.
  String get redirectingFactoryTargetName {
    throw new UnsupportedError('${runtimeType}.redirectingFactoryTargetName');
  }

  /// Returns the [InstanceTypeParameterAccessState] for the member whose body
  /// is begin built.
  ///
  /// This is used to determine whether access to instance type parameters is
  /// allowed.
  InstanceTypeParameterAccessState get instanceTypeParameterAccessState {
    if (isDeclarationInstanceContext) {
      return InstanceTypeParameterAccessState.Allowed;
    } else {
      return InstanceTypeParameterAccessState.Disallowed;
    }
  }

  /// Returns `true` if the constructor whose initializers is being built, needs
  /// to include an implicit super initializer.
  bool needsImplicitSuperInitializer(CoreTypes coreTypes) => false;

  /// Registers that a `super` call has occurred in the body currently being
  /// built.
  ///
  /// This is used to mark the enclosing member node as having a super call.
  void registerSuperCall() {
    throw new UnsupportedError('${runtimeType}.registerSuperCall');
  }

  /// Returns `true` if the constructor by the given [name] is a cyclic
  /// redirecting generative constructor in the enclosing class or extension
  /// type.
  bool isConstructorCyclic(String name) {
    throw new UnsupportedError('${runtimeType}.isConstructorCyclic');
  }

  /// Returns the [ConstantContext] for the body currently being built.
  ConstantContext get constantContext => ConstantContext.none;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is a late field
  /// declaration.
  bool get isLateField => false;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is an abstract
  /// field declaration.
  bool get isAbstractField => false;

  // Coverage-ignore(suite): Not run.
  /// Returns `true` if the member whose body is being built is an external
  /// field declaration.
  bool get isExternalField => false;

  /// Returns `true` if the enclosing class of the member whose body is being
  /// built is marked as a `mixin` class.
  bool get isMixinClass => declarationContext.isMixinClass;

  /// Returns `true` if the enclosing class of the member whose body is being
  /// built is marked as an enum.
  bool get isEnumClass => declarationContext.isEnumClass;

  /// Returns the name of the enclosing class or extension type declaration.
  String get className => declarationContext.className;

  /// Returns the name of the superclass of the enclosing class.
  String get superClassName => declarationContext.superClassName;

  /// Substitute [fieldType] from the context of the enclosing class or
  /// extension type declaration of a generative constructor.
  ///
  /// This is used for generic extension type constructors where the type
  /// variable referring to the class type parameters must be substituted for
  /// the synthesized constructor type parameters.
  DartType substituteFieldType(DartType fieldType) {
    throw new UnsupportedError('${runtimeType}.substituteFieldType');
  }

  /// Registers that the field [builder] has been initialized in generative
  /// constructor whose body is being built.
  void registerInitializedField(SourcePropertyBuilder builder) {
    throw new UnsupportedError('${runtimeType}.registerInitializedField');
  }

  /// Returns the [VariableDeclaration] for the [index]th formal parameter
  /// declared in the constructor, factory, method, or setter currently being
  /// built.
  VariableDeclaration getFormalParameter(int index) {
    throw new UnsupportedError('${runtimeType}.getFormalParameter');
  }

  /// Returns the [VariableDeclaration] for the [index]th formal parameter
  /// declared in the constructor, factory, or method tear-off currently being
  /// built.
  VariableDeclaration? getTearOffParameter(int index) {
    throw new UnsupportedError('${runtimeType}.getTearOffParameter');
  }

  /// Returns the type context that should be used for return statement in body
  /// currently being built.
  DartType get returnTypeContext {
    throw new UnsupportedError('${runtimeType}.returnTypeContext');
  }

  /// Returns the return type of the constructor, factory, method, getter or
  /// setter currently being built.
  TypeBuilder get returnType {
    throw new UnsupportedError('${runtimeType}.returnType');
  }

  /// Returns the [FormalParameterBuilder]s for the formals of the member whose
  /// body is currently being built, including synthetically added formal
  /// parameters.
  List<FormalParameterBuilder>? get formals {
    throw new UnsupportedError('${runtimeType}.formals');
  }

  /// Computes the scope containing the initializing formals or super
  /// parameters of the constructor currently being built, using [parent] as
  /// the parent scope.
  ///
  /// If a constructor is not currently being built, [parent] is returned.
  LocalScope computeFormalParameterInitializerScope(LocalScope parent) {
    throw new UnsupportedError(
      '${runtimeType}.computeFormalParameterInitializerScope',
    );
  }

  /// This is called before parsing constructor initializers.
  ///
  /// The constructor initializers are parsed both in the outline and in the
  /// body building phases, so this clears the initializer parsed during the
  /// outline phases to avoid duplication.
  void prepareInitializers() {
    throw new UnsupportedError('${runtimeType}.prepareInitializers');
  }

  /// Adds [initializer] to generative constructor currently being built.
  bool addInitializer(
    CompilerContext compilerContext,
    ProblemReporting problemReporting,
    Initializer initializer,
    Uri fileUri,
  ) {
    throw new UnsupportedError('${runtimeType}.addInitializer');
  }

  /// Adds the inferred [Initializer] from the [inferenceResult] to generative
  /// constructor currently being built.
  bool addInferredInitializer(
    CompilerContext compilerContext,
    ProblemReporting problemReporting,
    InitializerInferenceResult inferenceResult,
    Uri fileUri,
  ) {
    throw new UnsupportedError('${runtimeType}.addInferredInitializer');
  }

  /// Infers the [initializer].
  InitializerInferenceResult inferInitializer({
    required TypeInferrer typeInferrer,
    required Uri fileUri,
    required Initializer initializer,
  }) {
    throw new UnsupportedError('${runtimeType}.inferInitializer');
  }

  // Coverage-ignore(suite): Not run.
  /// Returns the target for using the `augmented` expression in an augmenting
  /// member.
  AugmentSuperTarget? get augmentSuperTarget {
    return null;
  }

  /// Sets the [asyncModifier] of the function currently being built.
  // TODO(johnniwinther): Do we need this? Isn't this already available from the
  // outline?
  void setAsyncModifier(AsyncMarker asyncModifier) {
    throw new UnsupportedError("${runtimeType}.setAsyncModifier");
  }

  /// Registers [body] as the result of the body building.
  void registerFunctionBody(Statement body) {
    throw new UnsupportedError("${runtimeType}.registerFunctionBody");
  }

  /// Registers that the constructor has no body.
  void registerNoBodyConstructor() {
    throw new UnsupportedError("${runtimeType}.registerNoBodyConstructor");
  }

  /// Returns the type of `this` in the body being built.
  ///
  /// This is only used for classes. For extensions and extension types, `this`
  /// is handled via a synthetic this variable.
  InterfaceType? get thisType => declarationContext.thisType;
}

/// Interface that provides information for a [BodyBuilderContext] from the
/// enclosing class-like declaration or library.
abstract class BodyBuilderDeclarationContext {
  final LibraryBuilder _libraryBuilder;

  factory BodyBuilderDeclarationContext(
    LibraryBuilder libraryBuilder,
    DeclarationBuilder? declarationBuilder,
  ) {
    if (declarationBuilder != null) {
      if (declarationBuilder is SourceClassBuilder) {
        return new _SourceClassBodyBuilderDeclarationContext(
          libraryBuilder,
          declarationBuilder,
        );
      } else if (declarationBuilder is DillClassBuilder) {
        // Coverage-ignore-block(suite): Not run.
        return new _DillClassBodyBuilderDeclarationContext(
          libraryBuilder,
          declarationBuilder,
        );
      } else if (declarationBuilder is SourceExtensionTypeDeclarationBuilder) {
        return new _SourceExtensionTypeDeclarationBodyBuilderDeclarationContext(
          libraryBuilder,
          declarationBuilder,
        );
      } else {
        return new _DeclarationBodyBuilderDeclarationContext(
          libraryBuilder,
          declarationBuilder,
        );
      }
    } else {
      return new _TopLevelBodyBuilderDeclarationContext(libraryBuilder);
    }
  }

  BodyBuilderDeclarationContext._(this._libraryBuilder);

  Member? lookupSuperMember(
    ClassHierarchy hierarchy,
    Name name, {
    bool isSetter = false,
  }) {
    throw new UnsupportedError('${runtimeType}.lookupSuperMember');
  }

  Builder? lookupConstructor(Name name) {
    throw new UnsupportedError('${runtimeType}.lookupConstructor');
  }

  Initializer buildRedirectingInitializer(
    Builder constructorBuilder,
    ArgumentsImpl arguments, {
    required int fileOffset,
  }) {
    throw new UnsupportedError('${runtimeType}.buildRedirectingInitializer');
  }

  MemberLookupResult? lookupSuperConstructor(
    String name,
    LibraryBuilder accessingLibrary,
  ) {
    throw new UnsupportedError('${runtimeType}.lookupSuperConstructor');
  }

  LookupResult? lookupLocalMember(String name);

  bool get isExtensionTypeDeclaration => false;

  // Coverage-ignore(suite): Not run.
  bool get isExtensionDeclaration => false;

  bool get isMixinClass => false;

  // Coverage-ignore(suite): Not run.
  bool get isEnumClass => false;

  String get className {
    throw new UnsupportedError('${runtimeType}.className');
  }

  String get superClassName {
    throw new UnsupportedError('${runtimeType}.superClassName');
  }

  InterfaceType? get thisType => null;

  bool isConstructorCyclic(String source, String target) {
    throw new UnsupportedError('${runtimeType}.isConstructorCyclic');
  }

  bool get declaresConstConstructor => false;

  // Coverage-ignore(suite): Not run.
  bool isObjectClass(CoreTypes coreTypes) => false;
}

mixin _DeclarationBodyBuilderDeclarationContextMixin
    implements BodyBuilderDeclarationContext {
  DeclarationBuilder get _declarationBuilder;

  @override
  LookupResult? lookupLocalMember(String name) {
    return _declarationBuilder.lookupLocalMember(name, required: false);
  }

  @override
  InterfaceType? get thisType => _declarationBuilder.thisType;

  @override
  bool get isExtensionDeclaration => _declarationBuilder is ExtensionBuilder;
}

class _SourceClassBodyBuilderDeclarationContext
    extends BodyBuilderDeclarationContext
    with _DeclarationBodyBuilderDeclarationContextMixin {
  final SourceClassBuilder _sourceClassBuilder;

  _SourceClassBodyBuilderDeclarationContext(
    LibraryBuilder libraryBuilder,
    this._sourceClassBuilder,
  ) : super._(libraryBuilder);

  @override
  DeclarationBuilder get _declarationBuilder => _sourceClassBuilder;

  @override
  bool isConstructorCyclic(String source, String target) {
    return _sourceClassBuilder.checkConstructorCyclic(source, target);
  }

  @override
  bool get declaresConstConstructor =>
      _sourceClassBuilder.declaresConstConstructor;

  @override
  bool isObjectClass(CoreTypes coreTypes) {
    return coreTypes.objectClass == _sourceClassBuilder.cls;
  }

  @override
  Member? lookupSuperMember(
    ClassHierarchy hierarchy,
    Name name, {
    bool isSetter = false,
  }) {
    return _sourceClassBuilder.lookupInstanceMember(
      hierarchy,
      name,
      isSetter: isSetter,
      isSuper: true,
    );
  }

  @override
  SourceConstructorBuilder? lookupConstructor(Name name) {
    return _sourceClassBuilder.lookupConstructor(name);
  }

  @override
  Initializer buildRedirectingInitializer(
    covariant SourceConstructorBuilder constructorBuilder,
    ArgumentsImpl arguments, {
    required int fileOffset,
  }) {
    return new InternalRedirectingInitializer(
      constructorBuilder.invokeTarget as Constructor,
      arguments,
    )..fileOffset = fileOffset;
  }

  @override
  MemberLookupResult? lookupSuperConstructor(
    String name,
    LibraryBuilder accessingLibrary,
  ) {
    return _sourceClassBuilder.lookupSuperConstructor(name, accessingLibrary);
  }

  @override
  bool get isMixinClass {
    return _sourceClassBuilder.isMixinClass;
  }

  @override
  bool get isEnumClass {
    return _sourceClassBuilder is SourceEnumBuilder;
  }

  @override
  String get className {
    return _sourceClassBuilder.fullNameForErrors;
  }

  @override
  String get superClassName {
    if (_sourceClassBuilder.supertypeBuilder?.declaration is InvalidBuilder) {
      // Coverage-ignore-block(suite): Not run.
      // TODO(johnniwinther): Avoid reporting errors on missing constructors
      // on invalid super types.
      return _sourceClassBuilder.supertypeBuilder!.fullNameForErrors;
    }
    Class cls = _sourceClassBuilder.cls;
    cls = cls.superclass!;
    while (cls.isMixinApplication) {
      cls = cls.superclass!;
    }
    return cls.name;
  }
}

// Coverage-ignore(suite): Not run.
class _DillClassBodyBuilderDeclarationContext
    extends BodyBuilderDeclarationContext
    with _DeclarationBodyBuilderDeclarationContextMixin {
  @override
  final DillClassBuilder _declarationBuilder;

  _DillClassBodyBuilderDeclarationContext(
    LibraryBuilder libraryBuilder,
    this._declarationBuilder,
  ) : super._(libraryBuilder);

  @override
  Member? lookupSuperMember(
    ClassHierarchy hierarchy,
    Name name, {
    bool isSetter = false,
  }) {
    return _declarationBuilder.lookupInstanceMember(
      hierarchy,
      name,
      isSetter: isSetter,
      isSuper: true,
    );
  }
}

class _SourceExtensionTypeDeclarationBodyBuilderDeclarationContext
    extends BodyBuilderDeclarationContext
    with _DeclarationBodyBuilderDeclarationContextMixin {
  final SourceExtensionTypeDeclarationBuilder
  _sourceExtensionTypeDeclarationBuilder;

  _SourceExtensionTypeDeclarationBodyBuilderDeclarationContext(
    LibraryBuilder libraryBuilder,
    this._sourceExtensionTypeDeclarationBuilder,
  ) : super._(libraryBuilder);

  @override
  DeclarationBuilder get _declarationBuilder =>
      _sourceExtensionTypeDeclarationBuilder;

  @override
  SourceConstructorBuilder? lookupConstructor(Name name) {
    return _sourceExtensionTypeDeclarationBuilder.lookupConstructor(name);
  }

  @override
  bool isConstructorCyclic(String source, String target) {
    // TODO(johnniwinther): Implement this.
    return false;
  }

  @override
  Initializer buildRedirectingInitializer(
    covariant SourceConstructorBuilder constructorBuilder,
    ArgumentsImpl arguments, {
    required int fileOffset,
  }) {
    return new ExtensionTypeRedirectingInitializer(
      constructorBuilder.invokeTarget as Procedure,
      arguments,
    )..fileOffset = fileOffset;
  }

  @override
  String get className {
    return _sourceExtensionTypeDeclarationBuilder.fullNameForErrors;
  }

  @override
  bool get isExtensionTypeDeclaration => true;
}

class _DeclarationBodyBuilderDeclarationContext
    extends BodyBuilderDeclarationContext
    with _DeclarationBodyBuilderDeclarationContextMixin {
  @override
  final DeclarationBuilder _declarationBuilder;

  _DeclarationBodyBuilderDeclarationContext(
    LibraryBuilder libraryBuilder,
    this._declarationBuilder,
  ) : super._(libraryBuilder);
}

class _TopLevelBodyBuilderDeclarationContext
    extends BodyBuilderDeclarationContext {
  _TopLevelBodyBuilderDeclarationContext(LibraryBuilder libraryBuilder)
    : super._(libraryBuilder);

  @override
  // Coverage-ignore(suite): Not run.
  LookupResult? lookupLocalMember(String name) {
    return _libraryBuilder.lookupLocalMember(name);
  }
}

class LibraryBodyBuilderContext extends BodyBuilderContext {
  LibraryBodyBuilderContext(SourceLibraryBuilder libraryBuilder)
    : super(libraryBuilder, null, isDeclarationInstanceMember: false);
}

mixin _DeclarationBodyBuilderContext<T extends DeclarationBuilder>
    implements BodyBuilderContext {
  @override
  InstanceTypeParameterAccessState get instanceTypeParameterAccessState {
    return InstanceTypeParameterAccessState.Allowed;
  }
}

class ClassBodyBuilderContext extends BodyBuilderContext
    with _DeclarationBodyBuilderContext<SourceClassBuilder> {
  ClassBodyBuilderContext(SourceClassBuilder sourceClassBuilder)
    : super(
        sourceClassBuilder.libraryBuilder,
        sourceClassBuilder,
        isDeclarationInstanceMember: false,
      );
}

class EnumBodyBuilderContext extends BodyBuilderContext
    with _DeclarationBodyBuilderContext<SourceEnumBuilder> {
  EnumBodyBuilderContext(SourceEnumBuilder sourceEnumBuilder)
    : super(
        sourceEnumBuilder.libraryBuilder,
        sourceEnumBuilder,
        isDeclarationInstanceMember: false,
      );
}

class ExtensionBodyBuilderContext extends BodyBuilderContext
    with _DeclarationBodyBuilderContext<SourceExtensionBuilder> {
  ExtensionBodyBuilderContext(SourceExtensionBuilder sourceExtensionBuilder)
    : super(
        sourceExtensionBuilder.libraryBuilder,
        sourceExtensionBuilder,
        isDeclarationInstanceMember: false,
      );
}

class ExtensionTypeBodyBuilderContext extends BodyBuilderContext
    with _DeclarationBodyBuilderContext<SourceExtensionTypeDeclarationBuilder> {
  ExtensionTypeBodyBuilderContext(
    SourceExtensionTypeDeclarationBuilder sourceExtensionTypeDeclarationBuilder,
  ) : super(
        sourceExtensionTypeDeclarationBuilder.libraryBuilder,
        sourceExtensionTypeDeclarationBuilder,
        isDeclarationInstanceMember: false,
      );
}

class TypedefBodyBuilderContext extends BodyBuilderContext {
  TypedefBodyBuilderContext(SourceTypeAliasBuilder sourceTypeAliasBuilder)
    : super(
        sourceTypeAliasBuilder.libraryBuilder,
        null,
        isDeclarationInstanceMember: false,
      );
}

class ParameterBodyBuilderContext extends BodyBuilderContext {
  factory ParameterBodyBuilderContext(
    LibraryBuilder libraryBuilder,
    DeclarationBuilder? declarationBuilder,
    FormalParameterBuilder formalParameterBuilder,
  ) {
    return new ParameterBodyBuilderContext._(
      libraryBuilder,
      declarationBuilder,
      formalParameterBuilder,
    );
  }

  ParameterBodyBuilderContext._(
    LibraryBuilder libraryBuilder,
    DeclarationBuilder? declarationBuilder,
    FormalParameterBuilder formalParameterBuilder,
  ) : super(
        libraryBuilder,
        declarationBuilder,
        isDeclarationInstanceMember:
            formalParameterBuilder.isDeclarationInstanceMember,
      );
}

// Coverage-ignore(suite): Not run.
class ExpressionCompilerProcedureBodyBuildContext extends BodyBuilderContext {
  final Procedure _procedure;

  ExpressionCompilerProcedureBodyBuildContext(
    this._procedure,
    SourceLibraryBuilder libraryBuilder,
    DeclarationBuilder? declarationBuilder, {
    required bool isDeclarationInstanceMember,
  }) : super(
         libraryBuilder,
         declarationBuilder,
         isDeclarationInstanceMember: isDeclarationInstanceMember,
       );

  @override
  AugmentSuperTarget? get augmentSuperTarget {
    return null;
  }

  @override
  int get memberNameOffset => _procedure.fileOffset;

  @override
  void registerSuperCall() {
    _procedure.transformerFlags |= TransformerFlag.superCalls;
  }
}
